﻿using System;
using IOPvsOOP.Chain.IF;
using IOPvsOOP.Chain.NOIF;
using IOPvsOOP.Math.NOIF;
using IOPvsOOP.Null.IF;
using IOPvsOOP.Null.NOIF;
using IOPvsOOP.Polymorphism.IF;
using IOPvsOOP.Polymorphism.NOIF;
using IOPvsOOP.State.IF;
using IOPvsOOP.State.NOIF;
using IOPvsOOP.Status.IF;
using IOPvsOOP.Status.NOIF;
using IOPvsOOP.Visitor.NOIF;
using NUnit.Framework;

namespace IOPvsOOP
{
    [TestFixture]
    public class Tests
    {
        [Test]
        public void FooPool_IF()
        {
            var foo0 = new Foo();
            var foo1 = new Foo();
            var foo2 = new Foo();
            var foos = new Foo[] {foo0, foo1, foo2};
            var fooPool = new FooPool(foos);
            Assert.AreEqual(foo0, fooPool.Get());
            Assert.AreEqual(foo1, fooPool.Get());
            Assert.AreEqual(foo2, fooPool.Get());
            Assert.AreEqual(foo0, fooPool.Get());
        }

        [Test]
        public void FooPoolMath_NOIF()
        {
            var foo0 = new Foo();
            var foo1 = new Foo();
            var foo2 = new Foo();
            var foos = new Foo[] { foo0, foo1, foo2 };
            var foolPool = new FooPoolMath(foos);
            Assert.AreEqual(foo0, foolPool.Get());
            Assert.AreEqual(foo1, foolPool.Get());
            Assert.AreEqual(foo2, foolPool.Get());
            Assert.AreEqual(foo0, foolPool.Get());
        }

        [Test]
        public void SalaryCalculator_IF()
        {
            var salaryCalculator = new SalaryCalculatorEnum();
            var employee = new EmployeeEnum();
            employee.Days = 10;
            employee.Cluster = ClusterEnum.Leader;
            var result = salaryCalculator.Calculate(employee);
            Assert.AreEqual(450, result);
        }

        [Test]
        public void SalaryEmployeeCalculator_NOIF()
        {
            var leader = new LeaderPolymorphism(10);
            var result = leader.Salary();
            Assert.AreEqual(450, result);
        }

        [Test]
        public void SalaryEmployeeVisitorCalculator_NOIF()
        {
            var leader = new Leader(10);
            var result = leader.Ask(new SalaryCalculationVisitor());
            Assert.AreEqual(450, result);
        }
        
        [Test]
        public void SalaryWithBenefitCalculator_IF()
        {
            var salaryCalculator = new SalaryCalculatorEnum();
            var salaryBenefitCalculator = new SalaryBenefitCalculatorEnum(salaryCalculator);
            var employee = new EmployeeEnum();
            employee.Days = 10;
            employee.Cluster = ClusterEnum.Leader;
            var result = salaryBenefitCalculator.Calculate(employee);
            Assert.AreEqual(495, result);
        }

        [Test]
        public void SalaryEmployeeBenefitVisitorCalculator_NOIF()
        {
            var leader = new Leader(10);
            var salaryCalculation = new SalaryCalculationVisitor();
            var salaryBenefitCalculation = new SalaryBenefitCalculationVisitor(salaryCalculation);
            var result = leader.Ask(salaryBenefitCalculation);
            Assert.AreEqual(495, result);
        }

        [Test]
        public void NullResult_IF()
        {
            //var employee = new EmployeeRepositoryNullIF().Get("badcode");
            var employeeRepository = new EmployeeRepositoryNullIF();
            var employee = employeeRepository.GetOrNull("CLAPAT01");
            //if (employee!=null)
            Assert.AreEqual("Claudio", employee.Name);
        }

        [Test]
        public void CentralisedNullResult_NOIF()
        {
            //var employee = new EmployeeRepositoryNullNOIF().Get("badcode");
            var employeeRepository = new EmployeeRepositoryNullNOIF();
            var employee = employeeRepository.Get("CLAPAT01");

            employee.Ask(e => Assert.AreEqual("Claudio", e.Name));
        }

        [Test]
        public void ConvertNumber_IF()
        {
            int number;
            if (int.TryParse("38", out number))
                Assert.AreEqual(38, number);
            else
                Assert.Fail();
        }

        [Test]
        public void ConvertNumberWrapIf_NOIF()
        {
            Action action = Assert.Fail;
            ConvertNumberStatusNOIF.Parse("38", number =>
            {
                action = () => Assert.AreEqual(38, number);
            });
            action();
        }

        [Test]
        public void CatchExceptions_IF()
        {
            var promocode = new PromocodeStatusIF();
            try
            {
                promocode.Apply("g128g7d2g");
            }
            catch (AlreadyUsedPromocodeException)
            {
                Assert.Pass("Already used");    
            }
            catch (ExpiredPromocodeException)
            {
                Assert.Pass("Expired");
            }
            catch (NotValidPromocodeException)
            {
                Assert.Pass("Not valid");
            }
            Assert.Fail("no exception");
        }

        [Test]
        public void RemoveCatchExceptionsAndUseMessages_NOIF()
        {
            var promocode = new PromocodeStatusNOIF();
            promocode
                .AlreadyUsed(() => Assert.Pass("Already used"))
                .Expired(() => Assert.Pass("Expired"))
                .NotValid(() => Assert.Pass("Not valid"))
                .Apply("g128g7d2g");

            Assert.Fail("no exception");
        }

        [Test]
        public void FooSingletonLazyFactory_IF()
        {
            var fooFactory = new FooSingletonLazyFactoryIF();
            var foo = fooFactory.Get();
            var foo1 = fooFactory.Get();
            Assert.AreEqual(foo, foo1);
        }

        [Test]
        public void FooSingletonLazyFactory_NOIF()
        {
            var fooFactory = new FooSingletonLazyFactoryNOIF();
            var foo = fooFactory.Get();
            var foo1 = fooFactory.Get();
            Assert.AreEqual(foo, foo1);
        }

        [Test]
        public void FooPool_NOIF()
        {
            var foo0 = new Foo();
            var foo1 = new Foo();
            var foo2 = new Foo();
            var foos = new Foo[] { foo0, foo1, foo2 };
            var fooPool = new FooPoolChain(foos);
            Assert.AreEqual(foo0, fooPool.Get());
            Assert.AreEqual(foo1, fooPool.Get());
            Assert.AreEqual(foo2, fooPool.Get());
            Assert.AreEqual(foo0, fooPool.Get());
        }
    }
}